var Sprite = function(stage) {
    this.stage = stage;

    Sprite.parent.call(this);

    this.direction = 90;
    this.indexInLibrary = -1;
    this.isDraggable = false;
    this.isDragging = false;
    this.rotationStyle = 'normal';
    this.scale = 1;
    this.scratchX = 0;
    this.scratchY = 0;
    this.spriteInfo = {};
    this.visible = true;

    this.Hue = 240;
    this.penHue = 250;
    this.penSaturation = 100;
    this.penLightness = 50;

    this.penSize = 1;
    this.isPenDown = false;
    this.isSprite = true;
    this.bubble = null;
    this.saying = false;
    this.thinking = false;
    this.sayId = 0;
  };
  inherits(Sprite, Base);

  Sprite.prototype.fromJSON = function(data) {

    Sprite.parent.prototype.fromJSON.call(this, data);

    this.direction = data.direction;
    this.indexInLibrary = data.indexInLibrary;
    this.isDraggable = data.isDraggable;
    this.rotationStyle = data.rotationStyle;
    this.scale = data.scale;
    this.scratchX = data.scratchX;
    this.scratchY = data.scratchY;
    this.spriteInfo = data.spriteInfo;
    this.visible = data.visible;

    return this;
  };

  Sprite.prototype.clone = function() {
    var c = new Sprite(this.stage);

    c.isClone = true;
    c.costumes = this.costumes;
    c.currentCostumeIndex = this.currentCostumeIndex;
    c.objName = this.objName;
    c.soundRefs = this.soundRefs;
    c.sounds = this.sounds;

    var keys = Object.keys(this.vars);
    for (var i = keys.length; i--;) {
      var k = keys[i];
      c.vars[k] = this.vars[k];
    }

    var keys = Object.keys(this.lists);
    for (var i = keys.length; i--;) {
      var k = keys[i];
      c.lists[k] = this.lists[k].slice(0);
    }

    c.procedures = this.procedures;
    c.listeners = this.listeners;
    c.fns = this.fns;
    c.scripts = this.scripts;

    c.filters = {
      color: this.filters.color,
      fisheye: this.filters.fisheye,
      whirl: this.filters.whirl,
      pixelate: this.filters.pixelate,
      mosaic: this.filters.mosaic,
      brightness: this.filters.brightness,
      ghost: this.filters.ghost
    };

    c.direction = this.direction;
    c.indexInLibrary = this.indexInLibrary;
    c.isDraggable = this.isDraggable;
    c.rotationStyle = this.rotationStyle;
    c.scale = this.scale;
    c.volume = this.volume;
    c.scratchX = this.scratchX;
    c.scratchY = this.scratchY;
    c.visible = this.visible;
    c.penColor = this.penColor;
    
    // Pen color in RGB mode?
    c.penRGBA = this.penRGBA;
    // Pen color in RGBA
    c.penRed = this.penRed;
    c.penGreen = this.penGreen;
    c.penBlue = this.penBlue;
    c.penAlpha = this.penAlpha;
    //Pen color in HSL
    c.penHue = this.penHue;
    c.penSaturation = this.penSaturation;
    c.penLightness = this.penLightness;
    
    c.penSize = this.penSize;
    c.isPenDown = this.isPenDown;

    return c;
  };

  Sprite.prototype.mouseDown = function() {
    this.dragStartX = this.scratchX;
    this.dragStartY = this.scratchY;
    this.dragOffsetX = this.scratchX - this.stage.mouseX;
    this.dragOffsetY = this.scratchY - this.stage.mouseY;
    this.isDragging = true;
  };

  Sprite.prototype.mouseUp = function() {
    if (this.isDragging && this.scratchX === this.dragStartX && this.scratchY === this.dragStartY) {
      this.stage.triggerFor(this, 'whenClicked');
    }
    this.isDragging = false;
  };

  Sprite.prototype.forward = function(steps) {
    var d = (90 - this.direction) * Math.PI / 180;
    this.moveTo(this.scratchX + steps * Math.cos(d), this.scratchY + steps * Math.sin(d));
  };

  Sprite.prototype.moveTo = function(x, y) {
    var ox = this.scratchX;
    var oy = this.scratchY;
    if (ox === x && oy === y && !this.isPenDown) return;
    this.scratchX = x;
    this.scratchY = y;
    if (this.isPenDown && !this.isDragging) {
      var context = this.stage.penContext;
      if (this.penSize % 2 > .5 && this.penSize % 2 < 1.5) {
        ox -= .5;
        oy -= .5;
        x -= .5;
        y -= .5;
      }

      /*
      context.strokeStyle = this.penRGBA || 'hsl(' + this.penHue + ',' + this.penSaturation + '%,' + (this.penLightness > 100 ? 200 - this.penLightness : this.penLightness) + '%)';
      
      if(this.penSize > 2 * 480 / this.stage.penCanvas.width)
        this.dotPen();
      
      context.lineWidth = this.penSize;
      context.beginPath();
      context.moveTo(240 + ox, 180 - oy);
      context.lineTo(240 + x, 180 - y);
      context.stroke();    
      */			
      
      //calculate color for vertices
      var r, g, b, a;
      if(this.penRGBA){
        r = this.penRed;
        g = this.penGreen;
        b = this.penBlue;
        a = this.penAlpha;
      }
      else{
        var rgb = this.hsl2rgb(this.penHue, this.penSaturation, (this.penLightness > 100 ? 200 - this.penLightness : this.penLightness));
        r = rgb[0];
        g = rgb[1];
        b = rgb[2];
        a = 1;
      }
      
      /*
      console.log(this.penRGBA);
      console.log(this.penHue);
      console.log(this.penSaturation);
      console.log(this.penLightness);
      console.log(this.hsl2rgb(this.penHue, this.penSaturation, (this.penLightness > 100 ? 200 - this.penLightness : this.penLightness)));
      */
 
      var circleRes = Math.max(Math.ceil(this.penSize * Math.max(this.stage.zoomX, this.stage.zoomY)), 3);
 
			// Redraw when array is full.
			if(this.stage.penCoordIndex + 24 * (circleRes+1) > this.stage.penCoords.length){
				this.stage.renderPen(this.stage.penContext, this.stage.penContext.penShaderInfo, this.stage.penContext.penBuffers);
				this.stage.penCoordIndex = 0;
				this.stage.penLineIndex  = 0;
				this.stage.penColorIndex = 0;
			}
			
      // draw line
      {
      // first triangle
      // first coordinates
      this.stage.penCoords[this.stage.penCoordIndex] = ox;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = oy;
      this.stage.penCoordIndex++;

      // first coordinates supplement
      this.stage.penCoords[this.stage.penCoordIndex] = x;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = y;
      this.stage.penCoordIndex++;
      
      //first vertex description
      this.stage.penLines[this.stage.penLineIndex] = -Math.PI/2;
      this.stage.penLineIndex++;
      this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
      this.stage.penLineIndex++;
      
			
			
      // second coordinates
      this.stage.penCoords[this.stage.penCoordIndex] = x;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = y;
      this.stage.penCoordIndex++;

      // second coordinates supplement
      this.stage.penCoords[this.stage.penCoordIndex] = ox;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = oy;
      this.stage.penCoordIndex++;
      
      //second vertex description
      this.stage.penLines[this.stage.penLineIndex] = Math.PI/2;
      this.stage.penLineIndex++;
      this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
      this.stage.penLineIndex++;      
      
			
			
      // third coordinates
      this.stage.penCoords[this.stage.penCoordIndex] = ox;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = oy;
      this.stage.penCoordIndex++;

      // third coordinates supplement
      this.stage.penCoords[this.stage.penCoordIndex] = x;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = y;
      this.stage.penCoordIndex++;

      //second vertex description
      this.stage.penLines[this.stage.penLineIndex] = Math.PI/2;
      this.stage.penLineIndex++;
      this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
      this.stage.penLineIndex++;
      
      
      
      
      
      // second triangle
      // first coordinates
      this.stage.penCoords[this.stage.penCoordIndex] = ox;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = oy;
      this.stage.penCoordIndex++;

      // first coordinates supplement
      this.stage.penCoords[this.stage.penCoordIndex] = x;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = y;
      this.stage.penCoordIndex++;
      
      //first vertex description
      this.stage.penLines[this.stage.penLineIndex] = Math.PI/2;
      this.stage.penLineIndex++;
      this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
      this.stage.penLineIndex++;
      
			
			
      // second coordinates
      this.stage.penCoords[this.stage.penCoordIndex] = x;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = y;
      this.stage.penCoordIndex++;

      // second coordinates supplement
      this.stage.penCoords[this.stage.penCoordIndex] = ox;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = oy;
      this.stage.penCoordIndex++;
      
      //second vertex description
      this.stage.penLines[this.stage.penLineIndex] = -Math.PI/2;
      this.stage.penLineIndex++;
      this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
      this.stage.penLineIndex++;      
      
			
			
      // third coordinates
      this.stage.penCoords[this.stage.penCoordIndex] = x;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = y;
      this.stage.penCoordIndex++;

      // third coordinates supplement
      this.stage.penCoords[this.stage.penCoordIndex] = ox;
      this.stage.penCoordIndex++;
      this.stage.penCoords[this.stage.penCoordIndex] = oy;
      this.stage.penCoordIndex++;

      //second vertex description
      this.stage.penLines[this.stage.penLineIndex] = Math.PI/2;
      this.stage.penLineIndex++;
      this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
      this.stage.penLineIndex++;      
      }
      
     

      
      for(var i = 0; i < circleRes; i++){
        
        
        // first endcap
        // first coordinates
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y;
        this.stage.penCoordIndex++;

        // first coordinates supplement
        this.stage.penCoords[this.stage.penCoordIndex] = ox;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = oy;
        this.stage.penCoordIndex++;      

        // first vertex description
        this.stage.penLines[this.stage.penLineIndex] = 0;
        this.stage.penLineIndex++;
        this.stage.penLines[this.stage.penLineIndex] = 0;
        this.stage.penLineIndex++;       

        
        
         // second coordinates
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y;
        this.stage.penCoordIndex++;

        // second coordinates supplement
        this.stage.penCoords[this.stage.penCoordIndex] = ox;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = oy;
        this.stage.penCoordIndex++;      

        // second vertex description
        this.stage.penLines[this.stage.penLineIndex] = Math.PI/2 + i / circleRes * Math.PI;
        this.stage.penLineIndex++;
        this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
        this.stage.penLineIndex++; 
        
        
        
         // third coordinates
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y;
        this.stage.penCoordIndex++;

        // third coordinates supplement
        this.stage.penCoords[this.stage.penCoordIndex] = ox;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = oy;
        this.stage.penCoordIndex++;      

        // third vertex description
        this.stage.penLines[this.stage.penLineIndex] = Math.PI/2 + (i+1) / circleRes * Math.PI;
        this.stage.penLineIndex++;
        this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
        this.stage.penLineIndex++;     
        
        
        
        
        // second endcap
        // first coordinates
        this.stage.penCoords[this.stage.penCoordIndex] = ox;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = oy;
        this.stage.penCoordIndex++;

        // first coordinates supplement
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y;
        this.stage.penCoordIndex++;      

        // first vertex description
        this.stage.penLines[this.stage.penLineIndex] = 0;
        this.stage.penLineIndex++;
        this.stage.penLines[this.stage.penLineIndex] = 0;
        this.stage.penLineIndex++;       

        
        
         // second coordinates
        this.stage.penCoords[this.stage.penCoordIndex] = ox;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = oy;
        this.stage.penCoordIndex++;

        // second coordinates supplement
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y;
        this.stage.penCoordIndex++;      

        // second vertex description
        this.stage.penLines[this.stage.penLineIndex] = Math.PI/2 + i / circleRes * Math.PI;
        this.stage.penLineIndex++;
        this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
        this.stage.penLineIndex++; 
        
        
        
         // third coordinates
        this.stage.penCoords[this.stage.penCoordIndex] = ox;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = oy;
        this.stage.penCoordIndex++;

        // third coordinates supplement
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y;
        this.stage.penCoordIndex++;      

        // third vertex description
        this.stage.penLines[this.stage.penLineIndex] = Math.PI/2 + (i+1) / circleRes * Math.PI;
        this.stage.penLineIndex++;
        this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
        this.stage.penLineIndex++;         
      }
     
     
     
      
      // set color of vertices
      for(var i = 0; i < circleRes * 6 + 6; i++){
        this.stage.penColors[this.stage.penColorIndex] = r;
        this.stage.penColorIndex++;
        this.stage.penColors[this.stage.penColorIndex] = g;
        this.stage.penColorIndex++;
        this.stage.penColors[this.stage.penColorIndex] = b;
        this.stage.penColorIndex++;
        this.stage.penColors[this.stage.penColorIndex] = a;
        this.stage.penColorIndex++;
      }
      
      
      this.penState = true;
    }
    if (this.saying) {
      this.updateBubble();
    }
  };

  Sprite.prototype.dotPen = function() {
    var context = this.stage.penContext;
    var x = this.scratchX;
    var y = this.scratchY;
    /*
    context.fillStyle = this.penRGBA || 'hsl(' + this.penHue + ',' + this.penSaturation + '%,' + (this.penLightness > 100 ? 200 - this.penLightness : this.penLightness) + '%)';

    if(this.penSize <= 2 * 480 / this.stage.penCanvas.width){
      context.fillRect(240 + x - this.penSize, 180 - y, this.penSize, this.penSize);
    }
    else{
    context.beginPath();
      context.arc(240 + x, 180 - y, Math.floor(this.penSize / 2), 0, 2 * Math.PI, false);
      context.fill();
    }
    */
 
    //if(this.penSize > 2 * 480 / this.stage.penCanvas.width){
     
      //calculate color for vertices
      var r, g, b, a;
      if(this.penRGBA){
        r = this.penRed;
        g = this.penGreen;
        b = this.penBlue;
        a = this.penAlpha;
      }
      else{
        var rgb = this.hsl2rgb(this.penHue, this.penSaturation, (this.penLightness > 100 ? 200 - this.penLightness : this.penLightness));
        r = rgb[0];
        g = rgb[1];
        b = rgb[2];
        a = 1;
      }
   
      var circleRes = Math.max(Math.ceil(this.penSize * Math.max(this.stage.zoomX, this.stage.zoomY)), 3);
      
			// Redraw when array is full.
			if(this.stage.penCoordIndex + 12 * circleRes > this.stage.penCoords.length){
				this.stage.renderPen(this.stage.penContext, this.stage.penContext.penShaderInfo, this.stage.penContext.penBuffers);
				this.stage.penCoordIndex = 0;
				this.stage.penLineIndex  = 0;
				this.stage.penColorIndex = 0;
			}
			
      for(var i = 0; i < circleRes; i++){
        // first endcap
        // first coordinates
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y;
        this.stage.penCoordIndex++;

        // first coordinates supplement
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;      

        // first vertex description
        this.stage.penLines[this.stage.penLineIndex] = 0;
        this.stage.penLineIndex++;
        this.stage.penLines[this.stage.penLineIndex] = 0;
        this.stage.penLineIndex++;       

        
        
         // second coordinates
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y;
        this.stage.penCoordIndex++;

        // second coordinates supplement
        this.stage.penCoords[this.stage.penCoordIndex] = x+1;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y+1;
        this.stage.penCoordIndex++;      

        // second vertex description
        this.stage.penLines[this.stage.penLineIndex] = Math.PI/2 + i / circleRes * 2 * Math.PI;
        this.stage.penLineIndex++;
        this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
        this.stage.penLineIndex++; 
        
        
        
         // third coordinates
        this.stage.penCoords[this.stage.penCoordIndex] = x;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y;
        this.stage.penCoordIndex++;

        // third coordinates supplement
        this.stage.penCoords[this.stage.penCoordIndex] = x+1;
        this.stage.penCoordIndex++;
        this.stage.penCoords[this.stage.penCoordIndex] = y+1;
        this.stage.penCoordIndex++;      

        // third vertex description
        this.stage.penLines[this.stage.penLineIndex] = Math.PI/2 + (i+1) / circleRes * 2 * Math.PI;
        this.stage.penLineIndex++;
        this.stage.penLines[this.stage.penLineIndex] = this.penSize/2;
        this.stage.penLineIndex++;           
      }    
      
      // set color of vertices
      for(var i = 0; i < circleRes * 3; i++){
        this.stage.penColors[this.stage.penColorIndex] = r;
        this.stage.penColorIndex++;
        this.stage.penColors[this.stage.penColorIndex] = g;
        this.stage.penColorIndex++;
        this.stage.penColors[this.stage.penColorIndex] = b;
        this.stage.penColorIndex++;
        this.stage.penColors[this.stage.penColorIndex] = a;
        this.stage.penColorIndex++;
      }
    
    //}
  };
  
  Sprite.prototype.hsl2rgb = function(h, s, l){
    var r, g, b;
    
    h = (h % 360) / 360;
    s = s / 100;
    l = (l - 10) / 100;
    
    if(s == 0){
        r = g = b = l; // achromatic
    }else{
        var hue2rgb = function hue2rgb(p, q, t){
            if(t < 0) t += 1;
            if(t > 1) t -= 1;
            if(t < 1/6) return p + (q - p) * 6 * t;
            if(t < 1/2) return q;
            if(t < 2/3) return p + (q - p) * (2/3 - t) * 6;
            return p;
        }

        var q = l < 0.5 ? l * (1 + s) : l + s - l * s;
        var p = 2 * l - q;
        r = hue2rgb(p, q, h + 1/3);
        g = hue2rgb(p, q, h);
        b = hue2rgb(p, q, h - 1/3);
    }
    return [Math.min(Math.floor(r * 256), 255), Math.min(Math.floor(g * 256), 255), Math.min(Math.floor(b * 256), 255)];
  }

  Sprite.prototype.draw = function(context, noEffects) {
    
		if(this.stage.penCoordIndex){
      this.stage.renderPen(this.stage.penContext, this.stage.penContext.penShaderInfo, this.stage.penContext.penBuffers);
      this.stage.penCoordIndex = 0;
      this.stage.penLineIndex  = 0;
      this.stage.penColorIndex = 0;
		}		
		
    var costume = this.costumes[this.currentCostumeIndex];
    
    if (this.isDragging) {
      this.moveTo(this.dragOffsetX + this.stage.mouseX, this.dragOffsetY + this.stage.mouseY);
    }
    
    
    if (costume && costume.image.imgInfo) {

      var z = Math.max(this.stage.zoomX, this.stage.zoomY);
      
      var tempTest
			
      if(costume.resScale < Math.min(this.scale * SCALE * z, 8) && costume.isSvg){
        if(costume.image.imgInfo){
          this.stage.context.deleteTexture(costume.image.imgInfo.texture);
          costume.image.imgInfo = null;
        }
        if(costume.image.penImgInfo){
          this.stage.penContext.deleteTexture(costume.image.penImgInfo.texture);
          costume.image.penImgInfo = null;
        }
        if(costume.image.collisionImgInfo){
          this.stage.glCollisionContext.deleteTexture(costume.image.collisionImgInfo.texture);
          costume.image.collisionImgInfo = null;
        }        
        
        costume.resScale = Math.min(Math.ceil(this.scale * SCALE * z), 8);
        
        console.log('scaling: ' + costume.resScale);
        
        costume.render();
      }
      
      
      var imgInfo;      
      if(context.canvas.id === 'canvas')
        imgInfo = costume.image.imgInfo;
      else if(context.canvas.id === 'penCanvas')
        imgInfo = costume.image.penImgInfo;
      else
        imgInfo = costume.image.collisionImgInfo;
      
      var color = -this.filters.color / 100 * Math.PI;
      var fisheye = this.filters.fisheye < -100 ? 0 : -this.filters.fisheye / 100 - 1;
      var whirl = -this.filters.whirl / 100 * Math.PI;
      var pixelate = Math.pow(Math.abs(this.filters.pixelate * costume.scale * this.scale), 0.6) + 1;
      var mosaic = Math.floor(Math.abs((this.filters.mosaic + 5) / 10)) + 1;
	  
	  if(this.filters.brightness > 100){
		  
		  this.filters.brightness = 100;
	  }
	  
      var brightness = this.filters.brightness / 100;
	  
      var ghost = noEffects ? 1 : Math.max(0, Math.min(1, 1 - this.filters.ghost / 100));
		
      glDrawImage(
        context,
        context.useTouchingShader ? context.touchingShaderInfo : context.imgShaderInfo,
        context.imgBuffers,
        imgInfo,
        this.scratchX + (imgInfo.width / costume.resScale / 2 - costume.rotationCenterX) * this.scale * costume.scale * (this.rotationStyle === 'leftRight' && this.direction < 0 ? -1 : 1),
        this.scratchY + (-imgInfo.height / costume.resScale / 2 + costume.rotationCenterY) * this.scale * costume.scale,
        imgInfo.width/costume.resScale * costume.scale * this.scale * (this.rotationStyle === 'leftRight' && this.direction < 0 ? -1 : 1),
        imgInfo.height/costume.resScale * costume.scale * this.scale,
        this.rotationStyle === 'normal' ? - this.direction + 90 : 0,
        (-imgInfo.width / costume.resScale / 2 + costume.rotationCenterX) * this.scale * costume.scale * (this.rotationStyle === 'leftRight' && this.direction < 0 ? -1 : 1),
        (imgInfo.height / costume.resScale / 2 - costume.rotationCenterY) * this.scale * costume.scale,
        [color, fisheye, whirl, pixelate, mosaic, brightness, ghost],
        this.stage.tColor);
    }
	
	
	
  };

	function hsvToRgb(h, s, v) {
  var r, g, b;

  var i = Math.floor(h * 6);
  var f = h * 6 - i;
  var p = v * (1 - s);
  var q = v * (1 - f * s);
  var t = v * (1 - (1 - f) * s);

  switch (i % 6) {
    case 0: r = v, g = t, b = p; break;
    case 1: r = q, g = v, b = p; break;
    case 2: r = p, g = v, b = t; break;
    case 3: r = p, g = q, b = v; break;
    case 4: r = t, g = p, b = v; break;
    case 5: r = v, g = p, b = q; break;
  }

  return {r: r * 255,g: g * 255,b: b * 255 };
  }

	function rgbToHsv(r, g, b) {
  r /= 255, g /= 255, b /= 255;

  var max = Math.max(r, g, b), min = Math.min(r, g, b);
  var h, s, v = max;

  var d = max - min;
  s = max == 0 ? 0 : d / max;

  if (max == min) {
    h = 0; // achromatic
  } else {
    switch (max) {
      case r: h = (g - b) / d + (g < b ? 6 : 0); break;
      case g: h = (b - r) / d + 2; break;
      case b: h = (r - g) / d + 4; break;
    }

    h /= 6;
  }

  return {	 h: h,
			s: s,
			v: v };
  }
	
  Sprite.prototype.setDirection = function(degrees) {
    var d = degrees % 360;
    if (d > 180) d -= 360;
    if (d <= -180) d += 360;
    this.direction = d;
    if (this.saying) this.updateBubble();
  };

  
  //folgender code ist nur provisorisch hier		
	 Sprite.prototype.sayOLD = function(text, thinking) {		
	    text = '' + text;		
	    if (!text) {		
	      this.saying = false;		
	      if (!this.bubble) return;		
	      this.bubble.style.display = 'none';		
	      return ++this.sayId;		
	    }		
	    this.saying = true;		
	    this.thinking = thinking;		
	    if (!this.bubble) {		
	      this.bubble = document.createElement('div');		
	      this.bubble.style.zIndex = '1'; // pf say over lists fix		
	      this.bubble.style.maxWidth = ''+(127/14)+'em';		
	      this.bubble.style.minWidth = ''+(48/14)+'em';		
	      this.bubble.style.padding = ''+(8/14)+'em '+(10/14)+'em';		
	      this.bubble.style.border = ''+(3/14)+'em solid rgb(160, 160, 160)';		
	      this.bubble.style.borderRadius = ''+(10/14)+'em';		
	      this.bubble.style.background = '#fff';		
	      this.bubble.style.position = 'absolute';		
	      this.bubble.style.font = 'bold 14em sans-serif';		
	      this.bubble.style.whiteSpace = 'pre-wrap';		
	      this.bubble.style.wordWrap = 'break-word';		
		  this.bubble.style.textAlign = 'center';		
		  this.bubble.style.cursor = 'default';		
	      this.bubble.appendChild(this.bubbleText = document.createTextNode(''));		
	      this.bubble.appendChild(this.bubblePointer = document.createElement('div'));		
	      this.bubblePointer.style.position = 'absolute';		
	      this.bubblePointer.style.height = ''+(21/14)+'em';		
	      this.bubblePointer.style.width = ''+(44/14)+'em';		
	      this.bubblePointer.style.background = 'url(icons.svg) '+(-195/14)+'em '+(-4/14)+'em';		
	      this.bubblePointer.style.backgroundSize = ''+(320/14)+'em '+(96/14)+'em';		
	      this.stage.root.appendChild(this.bubble);		
	    } else { // tjvr		
	      this.stage.root.removeChild(this.bubble); 		
	      this.stage.root.appendChild(this.bubble);		
	    }		
	    this.bubblePointer.style.backgroundPositionX = ((thinking ? -259 : -195)/14)+'em';		
	    this.bubble.style.display = 'block';		
	    this.bubbleText.nodeValue = text;		
	    this.updateBubble();		
	    return ++this.sayId;		
	  };		
			
	  Base.prototype.say = function(text, thinking) { // moved to base	3117.	  
	    text = '' + text;		
	    if (!text) {		
	      this.saying = false;		
	      if (!this.bubble) return;		
	      this.bubble.style.display = 'none';		
	      return ++this.sayId;		
	    }this.saying = true;		
	    this.thinking = thinking;		
	    if (!this.bubble) {		
	      this.bubble = document.createElement('div');		
	      this.bubble.style.zIndex = '1'; // pf say over lists fix		
	      this.bubble.style.maxWidth = ''+(127/14)+'em';		
	      this.bubble.style.minWidth = ''+(48/14)+'em';		
	      this.bubble.style.padding = ''+(8/14)+'em '+(10/14)+'em';		
	      this.bubble.style.border = ''+(3/14)+'em solid rgb(160, 160, 160)';		
	      this.bubble.style.borderRadius = ''+(10/14)+'em';		
	      this.bubble.style.background = '#fff';		
	      this.bubble.style.position = 'absolute';		
	      this.bubble.style.font = 'bold 14em sans-serif';		
	      this.bubble.style.whiteSpace = 'pre-wrap';		
	      this.bubble.style.wordWrap = 'break-word';		
	      this.bubble.style.textAlign = 'center';		
	      this.bubble.style.cursor = 'default';		
	      this.bubble.appendChild(this.bubbleText = document.createTextNode(''));		
	      this.bubble.appendChild(this.bubblePointer = document.createElement('div'));		
	      this.bubblePointer.style.position = 'absolute';		
	      this.bubblePointer.style.height = ''+(21/14)+'em';		
	      this.bubblePointer.style.width = ''+(44/14)+'em';		
	      this.bubblePointer.style.background = 'url(icons.svg) '+(-195/14)+'em '+(-4/14)+'em';		
	      this.bubblePointer.style.backgroundSize = ''+(320/14)+'em '+(96/14)+'em';		
	      this.stage.root.appendChild(this.bubble);		
	    } else { // tjvr		
	      this.stage.root.removeChild(this.bubble); 		
	      this.stage.root.appendChild(this.bubble);		
	    }		
	    this.bubblePointer.style.backgroundPositionX = ((thinking ? -259 : -195)/14)+'em';		
	    this.bubble.style.display = 'block';		
	    this.bubbleText.nodeValue = text;		
	    this.updateBubble();		
	    return ++this.sayId;		
	  };		
  
  
  
  //Context for collision math
  var collisionCanvas = document.createElement('canvas');
  var collisionContext = collisionCanvas.getContext('2d');
  
  Sprite.prototype.touching = function(thing) {    
    var costume = this.costumes[this.currentCostumeIndex];

    if (thing === '_mouse_') {
      var bounds = this.rotatedBounds();
      var x = this.stage.rawMouseX;
      var y = this.stage.rawMouseY;
      if (x < bounds.left || y < bounds.bottom || x > bounds.right || y > bounds.top) {
        return false;
      }
      var cx = (x - this.scratchX) / this.scale
      var cy = (this.scratchY - y) / this.scale
      if (this.rotationStyle === 'normal' && this.direction !== 90) {
        var d = (90 - this.direction) * Math.PI / 180
        var ox = cx
        var s = Math.sin(d), c = Math.cos(d)
        cx = c * ox - s * cy
        cy = s * ox + c * cy
      } else if (this.rotationStyle === 'leftRight' && this.direction < 0) {
        cx = -cx
      }
      
      //var d = costume.context.getImageData(cx * costume.resScale * costume.bitmapResolution + costume.rotationCenterX * costume.resScale, cy * costume.resScale * costume.bitmapResolution + costume.rotationCenterY * costume.resScale, 1, 1).data;
      
      this.stage.glCollisionContext.scissor(this.stage.rawMouseX + 240, this.stage.rawMouseY + 179, 1, 1);
      
      this.stage.glCollisionContext.clear(this.stage.glCollisionContext.COLOR_BUFFER_BIT);
      this.stage.glCollisionContext.useTouchingShader = false;
      this.draw(this.stage.glCollisionContext, true);
      
      var d = new Uint8Array(4);
      
      
      this.stage.glCollisionContext.readPixels(
        this.stage.rawMouseX + 240,
        this.stage.rawMouseY + 179,
        1,
        1,
        this.stage.glCollisionContext.RGBA,
        this.stage.glCollisionContext.UNSIGNED_BYTE,
        d);
        
      this.stage.glCollisionContext.scissor(0, 0, 480, 360);
      
      return d[3] !== 0;
    } else if (thing === '_edge_') {
      var bounds = this.rotatedBounds();
      return bounds.left <= -240 || bounds.right >= 240 || bounds.top >= 180 || bounds.bottom <= -180;
    } else {
      if (!this.visible) return false;
      var sprites = this.stage.getObjects(thing);
      for (var i = sprites.length; i--;) {
        var sprite = sprites[i];
        if (!sprite.visible) continue;
		
		
		
        var mb = this.rotatedBounds();
        var ob = sprite.rotatedBounds();
		//console.log(sprite);
        if (mb.bottom >= ob.top || ob.bottom >= mb.top || mb.left >= ob.right || ob.left >= mb.right) {
          continue;
        }
        
        var left = Math.max(mb.left, ob.left);
        var top = Math.min(mb.top, ob.top);
        var right = Math.min(mb.right, ob.right);
        var bottom = Math.max(mb.bottom, ob.bottom);

        collisionCanvas.width = Math.max(right - left, 1);
        collisionCanvas.height = Math.max(top - bottom, 1);

        collisionContext.save();
        collisionContext.translate(-(left + 240), -(180 - top));

        //this.draw(collisionContext, true);
        //collisionContext.globalCompositeOperation = 'source-in';
        //sprite.draw(collisionContext, true);      
        
        this.stage.glCollisionContext.scissor(240 + left, 180 + bottom, Math.max(right - left, 1), Math.max(top - bottom, 1));
        
        this.stage.glCollisionContext.clear(this.stage.glCollisionContext.COLOR_BUFFER_BIT);
        this.stage.glCollisionContext.useTouchingShader = false;
        this.draw(this.stage.glCollisionContext, true);
        
        this.stage.glCollisionContext.touchingShaderInfo.blendSource = this.stage.glCollisionContext.DST_ALPHA;
        this.stage.glCollisionContext.touchingShaderInfo.blendDest = this.stage.glCollisionContext.ZERO;    
        this.stage.tColor = [0.0, 0.0, 0.0, 0.0]     
        this.stage.glCollisionContext.useTouchingShader = true;
        sprite.draw(this.stage.glCollisionContext, true);
        
        //collisionContext.restore();

        //var data = collisionContext.getImageData(0, 0, Math.max(right - left, 1), Math.max(top - bottom, 1)).data;

        costume = sprite.costumes[sprite.currentCostumeIndex];
        
        var data = new Uint8Array(Math.max(right - left, 1) * Math.max(top - bottom, 1) * 4);
        this.stage.glCollisionContext.readPixels(
          240 + left,
          180 + bottom,
          Math.max(right - left, 1),
          Math.max(top - bottom, 1),
          this.stage.glCollisionContext.RGBA,
          this.stage.glCollisionContext.UNSIGNED_BYTE,
          data);
       
       this.stage.glCollisionContext.scissor(0, 0, 480, 360);
       
        var length = data.length;
        for (var j = 0; j < length; j += 4) {
          if (data[j + 3]) {
			 
            return true;
          }
        }
      }
      return false;
    }
  };

  Sprite.prototype.touchingColor = function(rgb) {    
    var b = this.rotatedBounds();
    //collisionCanvas.width = Math.ceil(b.right - b.left);
    //collisionCanvas.height = Math.ceil(b.top - b.bottom);

    //collisionContext.save();
    //collisionContext.translate(-(240 + b.left), -(180 - b.top));
    
    /*
    this.stage.drawAllOn(collisionContext, this);
    collisionContext.globalCompositeOperation = 'destination-in';
    this.draw(collisionContext, true);
    */    
    

    
    //set context to size of sprite:
    //this.stage.glCollisionCanvas.width = Math.ceil(b.right - b.left);
    //this.stage.glCollisionCanvas.height = Math.ceil(b.top - b.bottom);
    //this.stage.glCollisionCanvas.collisionMode = b;
    
    this.stage.glCollisionContext.scissor(240 + b.left, 180 + b.bottom, Math.ceil(b.right) - Math.floor(b.left), Math.ceil(b.top) - Math.floor(b.bottom));
    
    this.stage.glCollisionContext.clear(this.stage.glCollisionContext.COLOR_BUFFER_BIT);
    this.stage.glCollisionContext.useTouchingShader = false;
    this.stage.drawAllOn(this.stage.glCollisionContext, this);

    
    this.stage.glCollisionContext.touchingShaderInfo.blendSource = this.stage.glCollisionContext.ZERO;
    this.stage.glCollisionContext.touchingShaderInfo.blendDest = this.stage.glCollisionContext.SRC_COLOR;
    this.stage.tColor = [0.0, 0.0, 0.0, 0.0]    
    this.stage.glCollisionContext.useTouchingShader = true;
    this.draw(this.stage.glCollisionContext, true);
 



 
    //collisionContext.restore();

    /*
    var width  = collisionCanvas.width;
    var height = collisionCanvas.height;
    
    if(width <= 0){
      width=1;
    }
    if(height <= 0){
      height=1;
    }
	  */
  
    //var data = collisionContext.getImageData(0, 0, width, height).data;
    
    //b.right = Math.min(b.right, 240);

    var tempTest = performance.now(); 
 
    var data = new Uint8Array((Math.ceil(b.right) - Math.floor(b.left)) * (Math.ceil(b.top) - Math.floor(b.bottom)) * 4);
    
    this.stage.glCollisionContext.finish();
    this.stage.glCollisionContext.readPixels(
      240 + b.left,
      180 + b.bottom,
      Math.ceil(b.right) - Math.floor(b.left),
      Math.ceil(b.top) - Math.floor(b.bottom),
      this.stage.glCollisionContext.RGBA,
      this.stage.glCollisionContext.UNSIGNED_BYTE,
      data);
      
    this.stage.glCollisionContext.scissor(0, 0, 480, 360);
 
    //console.log(performance.now() - tempTest);  
    
    //rgb = rgb & 0xffffff;
    var length = data.length;//Math.ceil(b.right - b.left) * Math.ceil(b.top - b.bottom) * 4;   
    for (var i = 0; i < length; i += 4) {
      if(((data[i] << 16 | data[i + 1] << 8 | data[i + 2]) & 0xf8f8f0) === (rgb & 0xf8f8f0) && (data[i + 3] === 0xff)){
        return true;
      }
    }
    return false;
  };
  
  Sprite.prototype.colorTouchingColor = function(rgb1, rgb2, first) {
    var b = this.rotatedBounds();
 
     this.stage.glCollisionContext.scissor(240 + b.left, 180 + b.bottom, Math.ceil(b.right) - Math.floor(b.left), Math.ceil(b.top) - Math.floor(b.bottom));
 
    this.stage.glCollisionContext.clear(this.stage.glCollisionContext.COLOR_BUFFER_BIT);
    this.stage.glCollisionContext.useTouchingShader = false;
    this.stage.drawAllOn(this.stage.glCollisionContext, this);  
    
    this.stage.glCollisionContext.touchingShaderInfo.blendSource = this.stage.glCollisionContext.ZERO;
    this.stage.glCollisionContext.touchingShaderInfo.blendDest = this.stage.glCollisionContext.SRC_COLOR;
    this.stage.tColor = [((rgb1 & 0xff0000) >> 16) / 255, ((rgb1 & 0x00ff00) >> 8) / 255, (rgb1 & 0x0000ff) / 255, 1.0];   
    this.stage.glCollisionContext.useTouchingShader = true;
    this.draw(this.stage.glCollisionContext, true);
    
    b.right = Math.min(b.right, 240);
    
    var data = new Uint8Array(Math.ceil(b.right - b.left) * Math.ceil(b.top - b.bottom) * 4);
    this.stage.glCollisionContext.finish();    
    this.stage.glCollisionContext.readPixels(
      240 + b.left,
      180 + b.bottom,
      b.right - b.left,
      b.top - b.bottom,
      this.stage.glCollisionContext.RGBA,
      this.stage.glCollisionContext.UNSIGNED_BYTE,
      data);
 
    this.stage.glCollisionContext.scissor(0, 0, 480, 360);
 
    //rgb = rgb & 0xffffff;
    var length = Math.ceil(b.right - b.left) * Math.ceil(b.top - b.bottom) * 4;   
    for (var i = 0; i < length; i += 4) {
      //if(Math.abs(data[i    ] - data[i + 1]) <= 4 &&
      //   Math.abs(data[i    ] - data[i + 2]) <= 4 &&
      //   Math.abs(data[i + 1] - data[i + 2]) <= 4){
      //  if(data[i + 2] === (rgb2 & 0x0000ff) && data[i + 3]){
      //    return true;
      //  }
      //}
      //else{
        if(((data[i] << 16 | data[i + 1] << 8 | data[i + 2]) & 0xf8f8f0) === (rgb2 & 0xf8f8f0) && data[i + 3]){
          return true;
        }
      //}
    }
    
    return false;    
  }

  Sprite.prototype.bounceOffEdge = function() {
    var b = this.rotatedBounds();
    var dl = 240 + b.left;
    var dt = 180 - b.top;
    var dr = 240 - b.right;
    var db = 180 + b.bottom;

    var d = Math.min(dl, dt, dr, db);
    if (d > 0) return;

    var dir = this.direction * Math.PI / 180;
    var dx = Math.sin(dir);
    var dy = -Math.cos(dir);

    switch (d) {
      case dl: dx = Math.max(0.2, Math.abs(dx)); break;
      case dt: dy = Math.max(0.2, Math.abs(dy)); break;
      case dr: dx = -Math.max(0.2, Math.abs(dx)); break;
      case db: dy = -Math.max(0.2, Math.abs(dy)); break;
    }

    this.direction = Math.atan2(dy, dx) * 180 / Math.PI + 90;
    if (this.saying) this.updateBubble();

    b = this.rotatedBounds();
    var x = this.scratchX;
    var y = this.scratchY;
    if (b.left < -240) x += -240 - b.left;
    if (b.top > 180) y += 180 - b.top;
    if (b.right > 240) x += 240 - b.left;
    if (b.bottom < -180) y += -180 - b.top;
  };

  Sprite.prototype.rotatedBounds = function() {
    var costume = this.costumes[this.currentCostumeIndex];

    var s = costume.scale * this.scale;
    var left = -costume.rotationCenterX * s;
    var top = costume.rotationCenterY * s;
    var right = left + costume.image.width * s / costume.resScale;
    var bottom = top - costume.image.height * s / costume.resScale;

    if (this.rotationStyle !== 'normal') {
      if (this.rotationStyle === 'leftRight' && this.direction < 0) {
        right = -left;
        left = right - costume.image.width * costume.scale * this.scale / costume.resScale;
      }
      return {
        left: this.scratchX + left,
        right: this.scratchX + right,
        top: this.scratchY + top,
        bottom: this.scratchY + bottom
      };
    }

    var mSin = Math.sin(this.direction * Math.PI / 180);
    var mCos = Math.cos(this.direction * Math.PI / 180);

    var tlX = mSin * left - mCos * top;
    var tlY = mCos * left + mSin * top;

    var trX = mSin * right - mCos * top;
    var trY = mCos * right + mSin * top;

    var blX = mSin * left - mCos * bottom;
    var blY = mCos * left + mSin * bottom;

    var brX = mSin * right - mCos * bottom;
    var brY = mCos * right + mSin * bottom;

    return {
      left: this.scratchX + Math.min(tlX, trX, blX, brX),
      right: this.scratchX + Math.max(tlX, trX, blX, brX),
      top: this.scratchY + Math.max(tlY, trY, blY, brY),
      bottom: this.scratchY + Math.min(tlY, trY, blY, brY)
    };
  };

  Sprite.prototype.showRotatedBounds = function() {
    var bounds = this.rotatedBounds();
    var div = document.createElement('div');
    div.style.outline = '1px solid red';
    div.style.position = 'absolute';
    div.style.left = (240 + bounds.left) + 'px';
    div.style.top = (180 - bounds.top) + 'px';
    div.style.width = (bounds.right - bounds.left) + 'px';
    div.style.height = (bounds.top - bounds.bottom) + 'px';
    this.stage.canvas.parentNode.appendChild(div);
  };

  Sprite.prototype.distanceTo = function(thing) {
    if (thing === '_mouse_') {
      var x = this.stage.mouseX;
      var y = this.stage.mouseY;
    } else {
      var sprite = this.stage.getObject(thing);
      if (!sprite) return 0;
      x = sprite.scratchX;
      y = sprite.scratchY;
    }
    return Math.sqrt((this.scratchX - x) * (this.scratchX - x) + (this.scratchY - y) * (this.scratchY - y));
  };

  Sprite.prototype.gotoObject = function(thing) {
    if (thing === '_mouse_') {
      this.moveTo(this.stage.mouseX, this.stage.mouseY);
    } else if (thing === '_random_') {
      var x = Math.round(480 * Math.random() - 240);
      var y = Math.round(360 * Math.random() - 180);
      this.moveTo(x, y);
    } else {
      var sprite = this.stage.getObject(thing);
      if (!sprite) return 0;
      this.moveTo(sprite.scratchX, sprite.scratchY);
    }
  };

  Sprite.prototype.pointTowards = function(thing) {
    if (thing === '_mouse_') {
      var x = this.stage.mouseX;
      var y = this.stage.mouseY;
    } else {
      var sprite = this.stage.getObject(thing);
      if (!sprite) return 0;
      x = sprite.scratchX;
      y = sprite.scratchY;
    }
    var dx = x - this.scratchX;
    var dy = y - this.scratchY;
    this.direction = dx === 0 && dy === 0 ? 90 : Math.atan2(dx, dy) * 180 / Math.PI;
    if (this.saying) this.updateBubble();
  };

  Sprite.prototype.say = function(text, thinking) {
    text = '' + text;
    if (!text) {
      this.saying = false;
      if (!this.bubble) return;
      this.bubble.style.display = 'none';
      return ++this.sayId;
    }
    this.saying = true;
    this.thinking = thinking;
    if (!this.bubble) {
      this.bubble = document.createElement('div');
      this.bubble.style.maxWidth = ''+(127/14)+'em';
      this.bubble.style.minWidth = ''+(48/14)+'em';
      this.bubble.style.padding = ''+(8/14)+'em '+(10/14)+'em';
      this.bubble.style.border = ''+(3/14)+'em solid rgb(160, 160, 160)';
      this.bubble.style.borderRadius = ''+(10/14)+'em';
      this.bubble.style.background = '#fff';
      this.bubble.style.position = 'absolute';
      this.bubble.style.font = 'bold 1.4em sans-serif';
      this.bubble.style.whiteSpace = 'pre-wrap';
      this.bubble.style.wordWrap = 'break-word';
      this.bubble.style.textAlign = 'center';
      this.bubble.style.cursor = 'default';
      this.bubble.appendChild(this.bubbleText = document.createTextNode(''));
      this.bubble.appendChild(this.bubblePointer = document.createElement('div'));
      this.bubblePointer.style.position = 'absolute';
      this.bubblePointer.style.height = ''+(21/14)+'em';
      this.bubblePointer.style.width = ''+(44/14)+'em';
      this.bubblePointer.style.background = 'url(/img/icons.svg) '+(-195/14)+'em '+(-4/14)+'em';
      this.bubblePointer.style.backgroundSize = ''+(320/14)+'em '+(96/14)+'em';
      this.stage.root.appendChild(this.bubble);
    }
    this.bubblePointer.style.backgroundPositionX = ((thinking ? -259 : -195)/14)+'em';
    this.bubble.style.display = 'block';
    this.bubbleText.nodeValue = text;
    this.updateBubble();
    return ++this.sayId;
  };

  Sprite.prototype.updateBubble = function() {
	  
	//var bWidth = this.bubble.offsetWidth;
	//var bHeight = Math.max(this.stage.zoomX, this.stage.zoomY * 0.75);
	  
    if (!this.visible || !this.saying) {
      this.bubble.style.display = 'none';
      return;
    }
    var b = this.rotatedBounds();
	var z = Math.max(this.stage.zoomX, this.stage.zoomY);
    var width = this.bubble.offsetWidth / z;
    var height = this.bubble.offsetHeight / z;
	
	var stageTop;
	var stageRight;
	if(this.stage.zoomX <= this.stage.zoomY){
		stageTop = 360;
		stageRight = 480 * this.stage.zoomX / this.stage.zoomY;		
	}
	else{
		stageTop = 360 * this.stage.zoomY / this.stage.zoomX;
		stageRight = 480;
	}
	
    var left = 240 + b.right;
	var bottom = stageTop - 180 + b.top;

	
    this.bubblePointer.style.top = ((height - 6) / 14) + 'em';
    if (left + width + 2 > stageRight) {
      this.bubble.style.right = ((stageRight - 240 - b.left) / 14) + 'em';
      this.bubble.style.left = 'auto';
      this.bubblePointer.style.right = (3/14)+'em';
      this.bubblePointer.style.left = 'auto';
      this.bubblePointer.style.backgroundPositionY = (-36/14)+'em';
    } else {
      this.bubble.style.left = (left / 14) + 'em';
      this.bubble.style.right = 'auto';
      this.bubblePointer.style.left = (3/14)+'em';
      this.bubblePointer.style.right = 'auto';
      this.bubblePointer.style.backgroundPositionY = (-4/14)+'em';
    }
    if (bottom + height + 2 > stageTop) {
      bottom = stageTop - height - 2;
    }
    if (bottom < 19) {
      bottom = 19;
    }
    this.bubble.style.bottom = (bottom / 14) + 'em';
  };

  Sprite.prototype.remove = function() {
    if (this.bubble) {
      this.stage.root.removeChild(this.bubble);
      this.bubble = null;
    }
    if (this.node) {
      this.node.disconnect();
      this.node = null;
    }
  };